package com.leetroll.app.annotation.log;

import com.leetroll.app.global.SysConf;
import com.leetroll.common.enums.EBehavior;
import com.leetroll.common.holder.RequestHolder;
import com.leetroll.common.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 日志切面
 */
@Aspect
@Component("WebLoggerAspect")
@Slf4j
public class LoggerAspect {

    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;

    private final  RedisUtil redisUtil;

    @Autowired
    public LoggerAspect(ThreadPoolTaskExecutor threadPoolTaskExecutor, RedisUtil redisUtil) {
        this.threadPoolTaskExecutor=threadPoolTaskExecutor;
        this.redisUtil = redisUtil;
    }


    @Pointcut(value = "@annotation(bussinessLog)")
    public void pointcut(BussinessLog bussinessLog) {

    }

    @Around(value = "pointcut(bussinessLog)", argNames = "joinPoint,bussinessLog")
    public Object doAround(ProceedingJoinPoint joinPoint, BussinessLog bussinessLog) throws Throwable {

        //先执行业务
        Object result = joinPoint.proceed();

        try {
            // 日志收集
            handle(joinPoint);

        } catch (Exception e) {
            log.error("日志记录出错!", e);
        }

        return result;
    }

    private void handle(ProceedingJoinPoint point) throws Exception {
        //请求
        HttpServletRequest request = RequestHolder.getRequest();
        //当前方法
        Method currentMethod = AspectUtil.INSTANCE.getMethod(point);
        //获取注解
        BussinessLog annotation = currentMethod.getAnnotation(BussinessLog.class);

        //获取注解中参数
        boolean save = annotation.save();
        EBehavior behavior = annotation.behavior();
        String bussinessName = AspectUtil.INSTANCE.parseParams(point.getArgs(), annotation.value());

        String userAgent = RequestUtil.getUa();

        assert request != null;
        log.info("{} | {} - {} {} - {}", bussinessName, IpUtils.getIpAddr(request), RequestUtil.getMethod(), RequestUtil.getRequestUrl(), userAgent);
        if (!save) {
            return;
        }

        // 获取参数名称和值
        Map<String, Object> nameAndArgsMap = AopUtils.getFieldsName(point);

        //获取用户行为操作
        Map<String, String> result = EBehavior.getModuleAndOtherData(behavior, nameAndArgsMap, bussinessName);

        String userId = "";
        if (request.getAttribute(SysConf.USER_ID) != null) {
            userId = request.getAttribute(SysConf.USER_ID).toString();
        }

        //获取操作系统,浏览器及浏览器版本信息
        Map<String, String> map = IpUtils.getOsAndBrowserInfo(request);
        String os = map.get(SysConf.OS);
        String browser = map.get(SysConf.BROWSER);
        String ip = IpUtils.getIpAddr(request);

        // 异步存储日志
        threadPoolTaskExecutor.execute(
                new SysLogHandle(userId,
                        ip,
                        os,
                        browser,
                        behavior.getBehavior(),
                        result.get(SysConf.MODULE_ID),
                        result.get(SysConf.OTHER_DATA),
                        redisUtil));
    }
}
